package inspire13.duckhuntroid;

import java.util.Vector;

import android.content.Context;
import android.graphics.Canvas;

enum DuckState
{
	START,
	FLY,
	HIT,
	DIE,
	ESCAPE,
	END,
}

enum Direction
{
	POSITIVE,
	NEGATIVE,
	RANDOM,
}

public class Duck 
{
	private Sprite mDuckSprite;
	private int mX;
	private int mY;
	private int mWidth;
	private int mHeight;
	private int mMaxWidth; // Boundaries that duck can move
	private int mMaxHeight; // Boundaries that duck can move
	private DuckState mState;
	private Vector2f mSpeed;
	private float mMinSpeed;
	private float mMaxSpeed;
	private float mHitTimer;
	
	private static final int SPRITE_WIDTH  = 120;    // 36 on actual image
	private static final int SPRITE_HEIGHT = 120;    // 36 on actual image
	private static final int GRASS_LIMIT = 587;      // Grass limit
	private static final float MIN_SPEED  = 40.0f;   // mMinSpeed start value
	private static final float MAX_SPEED  = 60.0f;   // mMaxSpeed start value
	private static final float FALL_SPEED = 70.0f;   // Fall speed of duck 
	private static final float ANIM_DELAY = 0.1f;    // sprite animation delay
	private static final float HIT_DELAY  = 2.0f;    // Maximum delay for duck hit animation
	
	
	public Duck()
	{
		mDuckSprite = null;
		mX 			= 0;
		mY 			= 0;
		mWidth  	= SPRITE_WIDTH;
		mHeight 	= SPRITE_HEIGHT;
		mMaxWidth   = 0;
		mMaxWidth   = 0;
		mState 		= DuckState.START;
		mSpeed 		= new Vector2f();
		mMinSpeed   = MIN_SPEED;
		mMaxSpeed   = MAX_SPEED;
		mHitTimer 	= 0.0f;
	}
	
		
	public void LoadSprites(Context context)
	{
		mDuckSprite = new Sprite(mWidth, mHeight);
        
        Animation duckFlyUpRight = new Animation("flyUpRight", true);
        duckFlyUpRight.AddFrame(context.getResources().getDrawable(R.drawable.duck_up_right_0));
        duckFlyUpRight.AddFrame(context.getResources().getDrawable(R.drawable.duck_up_right_1));
        duckFlyUpRight.AddFrame(context.getResources().getDrawable(R.drawable.duck_up_right_2));
        mDuckSprite.AddAnimation(duckFlyUpRight);
        
        Animation duckFlyRight = new Animation("flyRight", true);
        duckFlyRight.AddFrame(context.getResources().getDrawable(R.drawable.duck_right_0));
        duckFlyRight.AddFrame(context.getResources().getDrawable(R.drawable.duck_right_1));
        duckFlyRight.AddFrame(context.getResources().getDrawable(R.drawable.duck_right_2));
        mDuckSprite.AddAnimation(duckFlyRight);
        
        Animation duckFlyLeft = new Animation("flyLeft", true);
        duckFlyLeft.AddFrame(context.getResources().getDrawable(R.drawable.duck_left_0));
        duckFlyLeft.AddFrame(context.getResources().getDrawable(R.drawable.duck_left_1));
        duckFlyLeft.AddFrame(context.getResources().getDrawable(R.drawable.duck_left_2));
        mDuckSprite.AddAnimation(duckFlyLeft);
        
        Animation duckUpFlyLeft = new Animation("flyUpLeft", true);
        duckUpFlyLeft.AddFrame(context.getResources().getDrawable(R.drawable.duck_up_left_0));
        duckUpFlyLeft.AddFrame(context.getResources().getDrawable(R.drawable.duck_up_left_1));
        duckUpFlyLeft.AddFrame(context.getResources().getDrawable(R.drawable.duck_up_left_2));
        mDuckSprite.AddAnimation(duckUpFlyLeft);
        
        Animation duckUpFly = new Animation("flyUp", true);
        duckUpFly.AddFrame(context.getResources().getDrawable(R.drawable.duck_up_0));
        duckUpFly.AddFrame(context.getResources().getDrawable(R.drawable.duck_up_1));
        duckUpFly.AddFrame(context.getResources().getDrawable(R.drawable.duck_up_2));
        mDuckSprite.AddAnimation(duckUpFly);
        
        Animation duckFall = new Animation("fall", true);
        duckFall.AddFrame(context.getResources().getDrawable(R.drawable.duck_fall_0));
        duckFall.AddFrame(context.getResources().getDrawable(R.drawable.duck_fall_1));
        mDuckSprite.AddAnimation(duckFall);
        
        Animation duckHit = new Animation("hit", true);
        duckHit.AddFrame(context.getResources().getDrawable(R.drawable.duck_hit));
        mDuckSprite.AddAnimation(duckHit);
	}
	
	public int GetX()
	{
		return mX;
	}
	
	public int GetY()
	{
		return mY;
	}
	
	public int GetWidth()
	{
		return mWidth;
	}
	
	public int GetHeight()
	{
		return mHeight;
	}
	
	public void SetScale(float scaleX, float scaleY)
	{
		mDuckSprite.SetScale(scaleX, scaleY);
		mWidth  = mDuckSprite.GetWidth();
		mHeight = mDuckSprite.GetHeight();
		mMaxWidth = DuckHuntroidView.CANVAS_HEIGHT; // Height is the width
		mMaxHeight = (int)(GRASS_LIMIT * scaleY);
	}
	
	public void Update(float deltaTime)
	{
		// DUCK AI
		switch (mState)
		{
			case START:
				StartState();
			break;
			
			case FLY:
				FlyState(deltaTime);
			break;
				
			case HIT:
				HitState(deltaTime);
			break;
			
			case DIE:
				DieState(deltaTime);
			break;
			
			case ESCAPE:
				EscapeState(deltaTime);
			break;
			
			case END:
				EndState(deltaTime);
			break;

			default:
			break;
		}
		
		mDuckSprite.UpdateAnimation(deltaTime);
	}
	
	public void Draw(Canvas canvas)
	{
		mDuckSprite.Draw(canvas);
	}
	
	public void Hit()
	{
		if(mState == DuckState.FLY)
		{
			mState = DuckState.HIT;
			mDuckSprite.PlayAnimation("hit", ANIM_DELAY);
		}
	}
	
	private void EndState(float deltaTime)
	{
		mDuckSprite.PlayAnimation("", ANIM_DELAY);
	}
	
	private void EscapeState(float deltaTime)
	{
		
	}
	
	private void DieState(float deltaTime)
	{
		mSpeed.X = 0;
		mSpeed.Y = FALL_SPEED;
		
		if(mY > mMaxHeight - mHeight)
		{
			mSpeed.Y = 0.0f;
			mState = DuckState.END;
		}
		
		ApplySpeed(deltaTime);
		mDuckSprite.SetLocation(mX, mY);
	}
	
	private void HitState(float deltaTime)
	{
		mSpeed.X = 0.0f;
		mSpeed.Y = 0.0f;
		
		if(mHitTimer > HIT_DELAY)
		{
			mDuckSprite.PlayAnimation("fall", ANIM_DELAY);
			mHitTimer = 0.0f;
			mState = DuckState.DIE;
		}
		
		ApplySpeed(deltaTime);
		mDuckSprite.SetLocation(mX, mY);
		
		mHitTimer += deltaTime;
	}
	
	private void StartState()
	{
		// make a random start point
		int minX = mWidth;
		int maxX = mMaxWidth - mWidth;
		
		int startX = minX + (int)(Math.random() * ((maxX - minX) + 1));
		int startY = mMaxHeight - mHeight;
		
		mX = startX;
		mY = startY;
		mDuckSprite.SetLocation(mX, mY);
		
		// make random start speed
		mSpeed.X = RandomDirectionSpeed(Direction.RANDOM);
		mSpeed.Y = RandomDirectionSpeed(Direction.NEGATIVE);
		
		mState = DuckState.FLY;
	}
	
	private void FlyState(float deltaTime)
	{
		ApplySpeed(deltaTime);
		BoundaryCheck();
		SetAnimationOfDirection();
		mDuckSprite.SetLocation(mX, mY);
	}
	
	private float RandomSpeed()
	{
		return mMinSpeed + (float)(Math.random() * ((mMaxSpeed - mMinSpeed)));
	}
	
	private float RandomDirectionSpeed(Direction direction)
	{
		float speed = RandomSpeed();
		
		switch (direction)
		{
			case RANDOM:
				int flip = (int)(Math.random() * 2); // Random: [0-1]
				if(flip == 0)
					speed = -speed;
			break;
			
			case POSITIVE:
				//speed = speed; do nothing
			break;
			
			case NEGATIVE:
				speed = -speed;
			break;
						
			default:
			break;
		}
		
		return speed;
	}
	
	private void ApplySpeed(float deltaTime)
	{
		mX = (int)(mX + mSpeed.X*deltaTime);
		mY = (int)(mY + mSpeed.Y*deltaTime);
	}
	
	private void BoundaryCheck()
	{
		int maxX = mMaxWidth - mWidth;
		int maxY = mMaxHeight - (mHeight + mHeight/2);
		
		if(mX > maxX)
		{
			mSpeed.X = RandomDirectionSpeed(Direction.NEGATIVE);
			mSpeed.Y = RandomDirectionSpeed(Direction.RANDOM);
		}
		
		if(mX < 0)
		{
			mSpeed.X = RandomDirectionSpeed(Direction.POSITIVE);
			mSpeed.Y = RandomDirectionSpeed(Direction.RANDOM);
		}
			
		if(mY > maxY)
		{
			mSpeed.X = RandomDirectionSpeed(Direction.RANDOM);
			mSpeed.Y = RandomDirectionSpeed(Direction.NEGATIVE);
		}
		
		if(mY < 0)
		{
			mSpeed.X = RandomDirectionSpeed(Direction.RANDOM);
			mSpeed.Y = RandomDirectionSpeed(Direction.POSITIVE);
		}
	}
	
	private void SetAnimationOfDirection()
	{
		boolean isRight    = mSpeed.X > 0;
		boolean isVertical = Math.abs(mSpeed.Y) > Math.abs(mSpeed.X); 
		
		if(isRight) // RIGHT
		{
			if(isVertical)
				mDuckSprite.PlayAnimation("flyUpRight", ANIM_DELAY);
			else
				mDuckSprite.PlayAnimation("flyRight", ANIM_DELAY);
		}
		else // LEFT
		{
			if(isVertical)
				mDuckSprite.PlayAnimation("flyUpLeft", ANIM_DELAY);
			else
				mDuckSprite.PlayAnimation("flyLeft", ANIM_DELAY);
		}
	}
}
